package com.yangyang.ralearn.common.entity.base;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.log4j.Logger;

import com.yangyang.ralearn.common.JEnvironment;
import com.yangyang.ralearn.common.entity.domain.RobotPredicate;
import com.yangyang.ralearn.common.types.JObject;
import com.yangyang.ralearn.common.types.JType;

/**
 * 含参数的谓词
 * 
 * @author yangyang
 * 
 */
public class ParamedPredicate extends BasePredicate implements
		Comparable<ParamedPredicate> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7565810994413846053L;
	private List<String> variables;

	public ParamedPredicate(JEnvironment environment, String name, String[] line) {
		super(environment, name, (JObject[]) null);
		this.variables = new ArrayList<String>();
		if (line != null && line.length > 0 && line[0] != null) {
			for (String var : line)
				variables.add(var);
		}
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if (!(obj instanceof ParamedPredicate))
			return false;
		ParamedPredicate pre = (ParamedPredicate) obj;
		return this.getName().equals(pre.getName())
				&& this.variables.equals(pre.variables);
	}

	public List<String> getParamVar() {
		return this.variables;
	}

	@Override
	protected Object clone() {
		// TODO Auto-generated method stub
		return new ParamedPredicate(environment, this.getName(),
				this.variables.toArray(new String[0]));
	}

	public AbstractDomainPredicate parsePredicate(
			Map<String, String> mapVar2Value) {
		AbstractDomainPredicate predicate = new RobotPredicate(environment,
				this.getName(), (JObject[]) null);
		for (String var : variables) {
			if (mapVar2Value.containsKey(var))
				predicate.paramValues.add(environment.mapName2Object
						.get(mapVar2Value.get(var)));
			else {
				Logger.getLogger(ParamedPredicate.class).error(
						" var :" + var + "has no value!");
			}
		}
		// Logger.getLogger(ParamedPredicate.class).debug(predicate);
		return predicate;
	}

	@Override
	public String toString() {
		return getName() + variables;
	}

	public static Set<ParamedPredicate> parseParamedPredicates(
			JEnvironment environment, BasePredicateDef def,
			Map<String, JType> mapVar2Type) {
		Set<ParamedPredicate> set = new HashSet<ParamedPredicate>();
		Set<ParamedPredicate> temp = new HashSet<ParamedPredicate>();
		set.add(new ParamedPredicate(environment, def.getName(), null));
		for (JType type : def.paramTypes) {
			temp.clear();
			for (ParamedPredicate pre : set) {
				for (Entry<String, JType> entry : mapVar2Type.entrySet()) {
					if (entry.getValue() == type) {
						if (!pre.variables.contains(entry.getKey())) {
							ParamedPredicate newPre = (ParamedPredicate) pre
									.clone();
							newPre.variables.add(entry.getKey());
							temp.add(newPre);
						}
					}
				}
			}
			set.clear();
			set.addAll(temp);
		}
		return set;
	}

	/**
	 * 判断两个谓词是否可以在一起，不可以在同一个位置（比如前提，效果） 出现的谓词不能放在一起(根据特定的规划问题确定）
	 * 
	 * (on ?x - block ?y - block) (ontable ?x - block) (clear ?x - block)
	 * (handempty) (holding ?x - block)
	 * 
	 * @param p1
	 * @param p2
	 * @return
	 */
	public static boolean canTogether(ParamedPredicate p1, ParamedPredicate p2) {
		if (p1.getName().equals("holding") && p2.getName().equals("handempty"))
			return false;
		if (p2.getName().equals("holding") && p1.getName().equals("handempty"))
			return false;
		if (p1.getName().equals("holding") && p2.getName().equals("holding"))
			return false;
		if (p1.getName().equals("on") && p2.getName().equals("on")) {
			if (p1.variables.get(0).equals(p2.variables.get(1))
					&& p1.variables.get(1).equals(p2.variables.get(0)))
				return false;
		}
		return true;
	}

	public static boolean canTogether(List<ParamedPredicate> list,
			ParamedPredicate p) {
		for (ParamedPredicate p1 : list) {
			if (!canTogether(p1, p))
				return false;
		}
		return true;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public int compareTo(ParamedPredicate o) {
		// TODO Auto-generated method stub
		return this.toString().compareTo(o.toString());
	}

}
